package com.meilai.project.service.app.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.meilai.project.constant.InstallTypeEnum;
import com.meilai.project.dto.app.VerInfoDTO;
import com.meilai.project.entity.business.building.BuildingArea;
import com.meilai.project.entity.business.installOrder.WorkOrder;
import com.meilai.project.entity.system.Dictionary;
import com.meilai.project.exception.CommonException;
import com.meilai.project.mapper.business.building.BuildingAreaMapper;
import com.meilai.project.mapper.business.installOrder.WorkOrderInstallDetailMapper;
import com.meilai.project.mapper.business.installOrder.WorkOrderInstallDetailPointMapper;
import com.meilai.project.mapper.business.installOrder.WorkOrderMapper;
import com.meilai.project.mapper.business.media.MediaPointMapper;
import com.meilai.project.mapper.business.media.MediaTypeMapper;
import com.meilai.project.mapper.business.sale.BillSaleMapper;
import com.meilai.project.mapper.personnel.org.RoleMapper;
import com.meilai.project.mapper.system.DictionaryMapper;
import com.meilai.project.mapper.system.UserMapper;
import com.meilai.project.service.app.AppExtraService;
import com.meilai.project.service.business.installOrder.WorkerSubmitService;
import com.meilai.project.service.system.DictionaryService;
import com.meilai.project.util.DateUtil;
import com.meilai.project.util.ThreadLocalUserUtil;
import com.meilai.project.vo.app.*;
import com.meilai.project.vo.business.installOrder.ProcessingWorkOrder5Ids;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 张驰
 * @date 2021/10/31 0:33
 */
@Service
@Log4j2
public class AppExtraServiceImpl implements AppExtraService {
    private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS");

    @Autowired
    private DictionaryService dictionaryService;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private MediaTypeMapper mediaTypeMapper;
    @Autowired
    private DictionaryMapper dictionaryMapper;
    @Autowired
    private BuildingAreaMapper buildingAreaMapper;
    @Autowired
    private MediaPointMapper mediaPointMapper;
    @Autowired
    private WorkOrderMapper workOrderMapper;
    @Autowired
    private BillSaleMapper billSaleMapper;
    @Autowired
    private WorkOrderInstallDetailMapper workOrderInstallDetailMapper;
    @Autowired
    private WorkOrderInstallDetailPointMapper workOrderInstallDetailPointMapper;
    @Autowired
    private WorkerSubmitService workerSubmitService;

    @Value("${web_domain}")
    private String web_domain;

    @Override
    public CompanyOfflineDataVO getCompanyOfflineData() {
        log.info("==============================");
        log.info("========开始拉取公司信息=========");

        CompanyOfflineDataVO result = new CompanyOfflineDataVO();

        try{
            Long userId = ThreadLocalUserUtil.get().getId();

            log.info("拉取设备类型开始：{}", DateUtil.getTimeLocalDateTime().format(dtf));
            List<CompanyOfflineMediaTypeDataVO> dicts = mediaTypeMapper.getMediaTypesForApp();
            if (CollectionUtils.isNotEmpty(dicts)) {
                result.setMedia_types(dicts);
            }
            log.info("拉取设备类型结束：{}", DateUtil.getTimeLocalDateTime().format(dtf));


            log.info("拉取故障原因开始：{}", DateUtil.getTimeLocalDateTime().format(dtf));
            List<Dictionary> bdts = dictionaryMapper.selectList(new QueryWrapper<Dictionary>()
                    .select("id", "name", "code", "memo").isNull("deleted_at").eq("status", 1)
                    .eq("level", 3).eq("rid", 1000).orderByAsc("sort","pid", "id"));
            bdts.forEach(d -> {
                CompanyOfflineBreakdownTypeDataVO vo = new CompanyOfflineBreakdownTypeDataVO();
                BeanUtils.copyProperties(d, vo);
                result.getBreakdown_types().add(vo);
            });
            log.info("拉取故障原因结束：{}", DateUtil.getTimeLocalDateTime().format(dtf));


            log.info("拉取画面属性开始：{}", DateUtil.getTimeLocalDateTime().format(dtf));
            List<Dictionary> picts = dictionaryMapper.selectList(new QueryWrapper<Dictionary>()
                    .select("id", "name", "code", "memo").isNull("deleted_at").eq("status", 1)
                    .eq("level", 3).eq("pid", 59).orderByAsc("pid", "id"));
            picts.forEach(d -> {
                CompanyOfflinePicTypeDataVO vo = new CompanyOfflinePicTypeDataVO();
                BeanUtils.copyProperties(d, vo);
                result.getPic_types().add(vo);
            });
            log.info("拉取画面属性结束：{}", DateUtil.getTimeLocalDateTime().format(dtf));


            log.info("拉取楼盘开始：{}", DateUtil.getTimeLocalDateTime().format(dtf));
            List<BuildingArea> buildings = buildingAreaMapper.selectList(new QueryWrapper<BuildingArea>()
                    .select("id", "photo", "name", "lat", "lng", "address", "created_at", "updated_at")
                    .isNull("deleted_at"));
            buildings.forEach(d -> {
                CompanyOfflineBuildingDataVO vo = new CompanyOfflineBuildingDataVO();
                BeanUtils.copyProperties(d, vo);
                result.getBuildings().add(vo);
            });
            log.info("拉取楼盘结束：{}", DateUtil.getTimeLocalDateTime().format(dtf));


            log.info("拉取设备开始：{}", DateUtil.getTimeLocalDateTime().format(dtf));
            List<CompanyOfflineDeviceDataVO> devices = mediaPointMapper.getAppDevicesData();
            if (CollectionUtils.isNotEmpty(devices)) result.setDevices(devices);
            log.info("拉取设备结束：{}", DateUtil.getTimeLocalDateTime().format(dtf));


            log.info("拉取工单开始：{}", DateUtil.getTimeLocalDateTime().format(dtf));
            log.info("工人id：{}", userId);
            CompanyOfflineDataVO temp = generateWorkOrderRemainDataVO(userId);
            log.info("工单数据：{}", JSON.toJSONString(temp));
            if(CollectionUtil.isEmpty(temp.getProcessing_work_orders())){
                log.error("获取工单数据异常");
            }
            result.setProcessing_work_orders(temp.getProcessing_work_orders());
            result.setProcessing_work_order_contracts(temp.getProcessing_work_order_contracts());
            result.setProcessing_work_order_contract_dateranges(temp.getProcessing_work_order_contract_dateranges());
            result.setProcessing_work_order_buildings(temp.getProcessing_work_order_buildings());
            result.setProcessing_work_order_building_remains(temp.getProcessing_work_order_building_remains());
            result.setProcessing_work_order_building_remain_devices(temp.getProcessing_work_order_building_remain_devices());
            log.info("拉取工单结束：{}", DateUtil.getTimeLocalDateTime().format(dtf));
        }catch(Exception e){
            log.error("拉取公司信息失败", e);
            return result;
        }
        log.info("========结束拉取公司信息=========");
        log.info("==============================");
        return result;
    }

    private List<ProcessingWorkOrder5Ids> getMain5Ids(Long workerId) {
        List<ProcessingWorkOrder5Ids> result = new ArrayList<>();
        int turn = 1;
        while (CollectionUtil.isEmpty(result) && turn <= 10) {
            if (turn > 1) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    // 处理中断异常
                    return result;
                }
            }
            result = workOrderMapper.getWorkerProcessingWorkOrder5Ids(workerId);
            turn++;
        }
        return result;
    }

    private CompanyOfflineDataVO generateWorkOrderRemainDataVO(Long workerId) {
        CompanyOfflineDataVO result = new CompanyOfflineDataVO();

        List<ProcessingWorkOrder5Ids> main5Ids = getMain5Ids(workerId);
        log.info("main5Ids：{}", JSON.toJSONString(main5Ids));
        HashSet<Long> set_workOrderId = new HashSet<>();
        HashSet<Long> set_workOrderId_unpublish = new HashSet<>(); // 下刊
        HashSet<Long> set_workOrderId_with_building = new HashSet<>(); // 新安装
        HashSet<Long> set_workOrderId_with_point = new HashSet<>(); // 楼盘相关巡检、维修
        HashSet<Long> set_workOrderId_from_bill = new HashSet<>(); // 上刊、下刊、销售单相关巡检
        HashMap<Long, HashSet<Long>> map_workOrderId_buildingAreaId = new HashMap<>();
        HashMap<Long, HashSet<Long>> map_workOrderId_daterangeId = new HashMap<>();
        if (CollectionUtils.isNotEmpty(main5Ids)) {
            for (ProcessingWorkOrder5Ids ids : main5Ids) {
                Long workOrderId = ids.getWork_order_id();
                Integer workOrderType = ids.getWork_order_type_id();
                Long billSaleId = ids.getBill_sale_id();
                Long daterangeId = ids.getDaterange_id();
                Long buildingAreaId = ids.getBuilding_area_id();
                if (workOrderId != null && buildingAreaId != null) {

                    HashSet<Long> set_buildingAreaId = map_workOrderId_buildingAreaId.getOrDefault(workOrderId, new HashSet<Long>());
                    set_buildingAreaId.add(buildingAreaId);
                    map_workOrderId_buildingAreaId.put(workOrderId, set_buildingAreaId);

                    if (billSaleId == null && daterangeId == null) {
                        if (workOrderType.equals(InstallTypeEnum.INSTALL.getInstallType())) {
                            set_workOrderId_with_building.add(workOrderId);
                        }
                        if (workOrderType.equals(InstallTypeEnum.CHECK.getInstallType())
                                || workOrderType.equals(InstallTypeEnum.REPAIR.getInstallType())) {
                            set_workOrderId_with_point.add(workOrderId);
                        }
                    }

                    if (billSaleId != null && daterangeId != null) {
                        set_workOrderId_from_bill.add(workOrderId);

                        if (workOrderType.equals(InstallTypeEnum.UNPUBLISH.getInstallType())) {
                            set_workOrderId_unpublish.add(workOrderId);
                        }

                        HashSet<Long> set_daterangeId = map_workOrderId_daterangeId.getOrDefault(workOrderId, new HashSet<Long>());
                        set_daterangeId.add(daterangeId);
                        map_workOrderId_daterangeId.put(workOrderId, set_daterangeId);
                    }

                }
            }
            log.info("set_workOrderId_unpublish：{}", JSON.toJSONString(set_workOrderId_unpublish));
            log.info("set_workOrderId_with_building：{}", JSON.toJSONString(set_workOrderId_with_building));
            log.info("set_workOrderId_with_point：{}", JSON.toJSONString(set_workOrderId_with_point));
            log.info("set_workOrderId_from_bill：{}", JSON.toJSONString(set_workOrderId_from_bill));

            set_workOrderId.addAll(set_workOrderId_with_building);
            set_workOrderId.addAll(set_workOrderId_with_point);
            set_workOrderId.addAll(set_workOrderId_from_bill);

            if (CollectionUtils.isNotEmpty(set_workOrderId)) {

                List<WorkOrder> wos = workOrderMapper.selectList(new QueryWrapper<WorkOrder>()
                        .select("id", "work_order_type_id", "name", "deadline", "remark", "bill_sale_id")
                        .isNull("deleted_at").eq("status", 1).in("id", set_workOrderId));
                if (CollectionUtils.isNotEmpty(wos)) {
                    HashSet<Long> set_billSaleId = new HashSet<>();

                    log.info("开始");
                    //log.info(JSON.toJSONString(wos));
                    List<CompanyOfflineWorkOrderProcessingDataVO> _wos = new ArrayList<>();
                    for (WorkOrder wo : wos) {
                        CompanyOfflineWorkOrderProcessingDataVO _wo = new CompanyOfflineWorkOrderProcessingDataVO();
                        BeanUtils.copyProperties(wo, _wo);
                        _wo.setWork_order_type_name(InstallTypeEnum.getName(wo.getWork_order_type_id()));
                        _wos.add(_wo);
                        if (wo.getBill_sale_id() != null) {
                            set_billSaleId.add(wo.getBill_sale_id());
                        }
                    }

                    log.info("步骤1");
                    //log.info(JSON.toJSONString(set_workOrderId_from_bill));
                    List<CompanyOfflineWorkOrderProcessingContractDataVO> contracts = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(set_workOrderId_from_bill))
                        contracts = billSaleMapper.queryContractsForApp(set_workOrderId_from_bill);
                    if (CollectionUtils.isNotEmpty(contracts)) result.setProcessing_work_order_contracts(contracts);

                    log.info("步骤2");

                    List<CompanyOfflineWorkOrderProcessingContractDateRangeDataVO> dateranges = new ArrayList<>();
                    List<CompanyOfflineWorkOrderProcessingContractDateRangeDataVO> dateranges_r = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(set_workOrderId_from_bill))
                        dateranges = billSaleMapper.queryDaterangesForApp(set_workOrderId_from_bill);
                    //log.info("打印dateranges: {}",JSON.toJSONString(dateranges));
                    if (CollectionUtils.isNotEmpty(dateranges)) {
                        // 当前人负责的楼盘的时间段挑出
                        dateranges_r = dateranges.stream().filter(d -> (
                                map_workOrderId_daterangeId.getOrDefault(d.getWork_order_id(), new HashSet<>()).contains(d.getDate_range_id())
                        )).collect(Collectors.toList());
                        //log.info("打印dateranges_r: {}",JSON.toJSONString(dateranges_r));
                        result.setProcessing_work_order_contract_dateranges(dateranges_r);
                    }

                    log.info("步骤3");

                    List<CompanyOfflineWorkOrderProcessingBuildingDataVO> buildings = new ArrayList<>();
                    List<CompanyOfflineWorkOrderProcessingBuildingDataVO> buildings_r = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(set_workOrderId))
                        buildings = workOrderInstallDetailMapper.queryBuildingsForApp(set_workOrderId);
                    //log.info("打印buildings: {}",JSON.toJSONString(buildings));
                    if (CollectionUtils.isNotEmpty(buildings)) {
                        // 当前人负责的楼盘挑出
                        buildings_r = buildings.stream().filter(d -> (
                                map_workOrderId_buildingAreaId.getOrDefault(d.getWork_order_id(), new HashSet<>()).contains(d.getBuilding_area_id())
                        )).collect(Collectors.toList());
                        //log.info("打印buildings_r: {}",JSON.toJSONString(buildings_r));
                        result.setProcessing_work_order_buildings(buildings_r);
                    }

                    log.info("步骤4");

                    // 剩余数量，新安装有值，其他为0
                    List<CompanyOfflineWorkOrderProcessingBuildingRemainDataVO> remains = new ArrayList<>();
                    List<CompanyOfflineWorkOrderProcessingBuildingRemainDataVO> remains_r = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(set_workOrderId))
                        remains = workOrderInstallDetailMapper.queryRemainsForApp(set_workOrderId);
                    //log.info("打印remains: {}",JSON.toJSONString(remains));
                    if (CollectionUtils.isNotEmpty(remains)) {
                        // 当前人负责的楼盘挑出
                        remains_r = remains.stream().filter(d -> (
                                map_workOrderId_buildingAreaId.getOrDefault(d.getWork_order_id(), new HashSet<>()).contains(d.getBuilding_area_id())
                        )).collect(Collectors.toList());
                        //log.info("打印remains_r: {}",JSON.toJSONString(remains_r));
                        result.setProcessing_work_order_building_remains(remains_r);
                    }

                    log.info("步骤5");

                    // 剩余指定，除了新安装外都有，由于下刊需要另外处理，此处剔除下刊的
                    List<CompanyOfflineWorkOrderProcessingBuildingRemainDeviceDataVO> remainDevices = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(set_workOrderId_from_bill)) {
                        List<CompanyOfflineWorkOrderProcessingBuildingRemainDeviceDataVO> remainDevices_bill = workOrderInstallDetailPointMapper.queryBillRemainDevicesForAppExceptUnPublish(set_workOrderId_from_bill);
                        //log.info("打印remainDevices_bill: {}",JSON.toJSONString(remainDevices_bill));
                        if (CollectionUtils.isNotEmpty(remainDevices_bill)) {
                            // 当前人负责的楼盘挑出
                            remainDevices.addAll(
                                    remainDevices_bill.stream().filter(d -> (
                                            map_workOrderId_buildingAreaId.getOrDefault(d.getWork_order_id(), new HashSet<>()).contains(d.getBuilding_area_id())
                                    )).collect(Collectors.toList())
                            );
                            //log.info("打印remainDevices: {}",JSON.toJSONString(remainDevices));
                        }
                    }

                    log.info("步骤6");

                    if (CollectionUtils.isNotEmpty(set_workOrderId_with_point)) {
                        List<CompanyOfflineWorkOrderProcessingBuildingRemainDeviceDataVO> remainDevices_notbill = workOrderInstallDetailPointMapper.queryNotBillRemainDevicesForApp(set_workOrderId_with_point);
                        //log.info("打印remainDevices_notbill: {}",JSON.toJSONString(remainDevices_notbill));
                        if (CollectionUtils.isNotEmpty(remainDevices_notbill)) {
                            // 当前人负责的楼盘挑出
                            remainDevices.addAll(
                                    remainDevices_notbill.stream().filter(d -> (
                                            map_workOrderId_buildingAreaId.getOrDefault(d.getWork_order_id(), new HashSet<>()).contains(d.getBuilding_area_id())
                                    )).collect(Collectors.toList())
                            );
                            //log.info("打印remainDevices: {}",JSON.toJSONString(remainDevices));
                        }
                    }

                    log.info("步骤7");

                    if (set_workOrderId_unpublish.size() == 0) {
                        set_workOrderId_unpublish.add(-1L);
                    }
                    // 针对下刊工单，处理
                    List<CompanyOfflineWorkOrderProcessingBuildingRemainDeviceDataVO> remainDevices_unPublish = workOrderInstallDetailPointMapper.queryUnPublishRemainDevicesForApp(set_workOrderId_unpublish);
                    //log.info("打印remainDevices_unPublish: {}",JSON.toJSONString(remainDevices_unPublish));
                    if (CollectionUtils.isNotEmpty(remainDevices_unPublish)) {
                        // 已提交
//                        List<RemainDeviceDataVO> submitDevices_unPublish = workOrderInstallDetailPointMapper.queryUnPublishSubmitDevicesForApp(set_workOrderId_unpublish);
//                        Map<String, Set<Long>> submitMap = new HashMap<>();
//                        if (CollectionUtils.isNotEmpty(submitDevices_unPublish)) {
//                            submitMap = submitDevices_unPublish.stream().collect(Collectors.groupingBy(d ->
//                                            d.getContract_id() + "_" + d.getDaterange_id()
//                                    , Collectors.mapping(RemainDeviceDataVO::getMedia_point_id, Collectors.toSet())));
//                        }
//
//                        // 应下刊
//                        Map<String, Set<Long>> finalSubmitMap = submitMap;
//                        remainDevices.addAll(
//                                remainDevices_unPublish.stream().filter(d -> (
//                                        map_workOrderId_buildingAreaId.getOrDefault(d.getWork_order_id(), new HashSet<>()).contains(d.getBuilding_area_id())
//                                                && !finalSubmitMap.getOrDefault(d.getContract_id() + "_" + d.getDate_range_id(), new HashSet<>()).contains(d.getDevice_id())
//                                )).collect(Collectors.toList())
//                        );
                        // todo 放开限制下刊点位
                        remainDevices.addAll(remainDevices_unPublish);
                        //log.info("打印remainDevices: {}",JSON.toJSONString(remainDevices));
                    }

                    log.info("结束");

                    result.setProcessing_work_order_building_remain_devices(remainDevices);

                    // 设置原系统类型id
//                    for (CompanyOfflineWorkOrderProcessingDataVO _wo : _wos) {
//                        _wo.setWork_order_type_id(InstallTypeEnum.getOldType(_wo.getWork_order_type_id()));
//                    }

                    result.setProcessing_work_orders(_wos);
                }

            }
        }

        return result;
    }

    @Override
    public MyInfoVO getMyInfo(HttpServletRequest request) {
        Long userId = ThreadLocalUserUtil.get().getId();
        MyInfoVO result = userMapper.getAppMyInfo(userId);
        result.setPost(roleMapper.getUserRoles(userId));
        return result;
    }

    @Override
    public VerInfoVO getVerInfo(VerInfoDTO dto) {
        VerInfoVO result = new VerInfoVO();
        List<Dictionary> vers = dictionaryService.list(new QueryWrapper<Dictionary>()
                .isNull("deleted_at").eq("status", 1).eq("code", "appxg-bbh-zxbb"));

        if (CollectionUtils.isEmpty(vers) && vers.size() > 1) throw new CommonException("获取最新版本失败，请联系管理员");
        Dictionary ver = vers.get(0);
        boolean needUpdate = dto == null || StringUtils.isEmpty(dto.getVersion());

        if (!needUpdate && StringUtils.isNotEmpty(ver.getParams())) {
            String[] tempVer = dto.getVersion().split("\\.");
            String[] curVer = ver.getParams().split("\\.");
            if (tempVer.length != 3) throw new CommonException("请传入正确的版本号，例如1.0.2");
            if (curVer.length != 3) throw new CommonException("获取最新版本失败，请联系管理员");

            needUpdate = false;

            int temp1 = Integer.parseInt(tempVer[0]);
            int cur1 = Integer.parseInt(curVer[0]);
            int temp2 = Integer.parseInt(tempVer[1]);
            int cur2 = Integer.parseInt(curVer[1]);
            int temp3 = Integer.parseInt(tempVer[2]);
            int cur3 = Integer.parseInt(curVer[2]);

            if (temp1 < cur1) needUpdate = true;
            if (temp1 == cur1 && temp2 < cur2) needUpdate = true;
            if (temp1 == cur1 && temp2 == cur2 && temp3 < cur3) needUpdate = true;
        }

        result.setNeed_update(needUpdate ? 1 : 0);
        result.setVersion(ver.getParams());
        result.setContext(needUpdate ? "检查当前有新版本，是否前往更新？" : "当前已是最新版本");
        result.setDownload_page(web_domain + "/#/app/app_download");
        result.setDownload_url(ver.getMemo());

        return result;
    }
}
